#pragma once
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<queue>

using namespace std;

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
//生产者和消费者的条件变量要分开的，它们是不同的
pthread_cond_t c_cond=PTHREAD_COND_INITIALIZER;//消费者的条件变量
pthread_cond_t p_cond=PTHREAD_COND_INITIALIZER;//生产者的条件变量

template<class T>
class BlockQueue
{
public:
    BlockQueue(int maxcap=4):_maxcap(maxcap)
    {}

    T pop()
    {
        //加锁
        pthread_mutex_lock(&mutex);
        // 我们怎么知道我们要让一个线程去休眠了那？一定是临界资源不就绪，没错，临界资源也是有状态的！！
        // 你怎么知道临界资源是就绪还是不就绪的？你判断出来的！判断是访问临界资源吗？必须是的，也就是判断必须在加锁之后！！！
        while(_wait_q.size()==0)//队列为空，临界资源不就绪，就不能消费了，在消费者条件变量下等待
        {
            pthread_cond_wait(&c_cond,&mutex);//1.pthread_cond_wait让线程等待的时候，会自动释放锁！2.唤醒而返回的时候，重新持有锁
        }
        T out=_wait_q.front();
        _wait_q.pop();
        pthread_cond_signal(&p_cond);//消费了一个，生产者肯定可以生产了，唤醒生产者的条件变量下的一个线程
        pthread_mutex_unlock(&mutex);
        return out;
    }
    void push(const T& in)
    {
        pthread_mutex_lock(&mutex);
        while(_wait_q.size()==_maxcap)//队列满了，临界资源不就绪，就不能生产了，在生产者条件变量下等待
        {
            pthread_cond_wait(&p_cond,&mutex);
        }
        _wait_q.push(in);
        pthread_cond_signal(&c_cond);//生产了一个，消费者肯定可以消费了，唤醒消费者的条件变量下的一个线程
        pthread_mutex_unlock(&mutex);
    }
    ~BlockQueue()
    {}

private:
    queue<T> _wait_q;//等待队列
    int _maxcap;//队列的最大容量

};